/*
Object Viewer Qt Widget
Copyright (C) 2010 Adrian Jaekel <aj at elane2k dot com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef ENTITY_H
#define ENTITY_H

#include <nel/misc/types_nl.h>

// STL includes
#include <map>
#include <string>
#include <vector>

// NeL includes
#include <nel/misc/vector.h>
#include <nel/misc/vectord.h>
#include <nel/misc/quat.h>
#include <nel/3d/animation_time.h>
#include <nel/3d/u_instance.h>
#include <nel/3d/u_skeleton.h>
#include <nel/3d/channel_mixer.h>

namespace NL3D 
{
	class UPlayList;
	class UAnimationSet;
}

namespace NLQT 
{

	class CSlotInfo
	{
	public:
		CSlotInfo ():
		  Animation("empty"), Skeleton("empty"),
			  Offset(0), StartTime(0), EndTime(0),
			  StartBlend(1),	EndBlend (1), Smoothness(1),
			  SpeedFactor(1),	ClampMode(0),
			  SkeletonInverted(false), 
			  Enable(true)	{} ;

		  std::string		Animation;
		  std::string		Skeleton;
		  float			Offset;
		  float			StartTime;
		  float			EndTime;

		  float			StartBlend;
		  float			EndBlend;
		  float			Smoothness;
		  float			SpeedFactor;
		  sint32			ClampMode;
		  bool			SkeletonInverted;
		  bool			Enable;

		  CSlotInfo &operator=(const CSlotInfo &);
	};


	/**
	@class CEntity
	@brief Class manage animated shape.
	@details
	Allows you to load animations for shape and skeleton weight. 
	Contains a built-in playlist. Has management and playback Playlists or Mixer.
	*/
	class CEntity
	{
	public:
		struct Mode
		{
			enum List
			{
				PlayList = 1,
				Mixer
			};
		};

		/// Will need for a single or multiple animation shape
		struct SAnimationStatus
		{
			bool	LoopAnim;
			bool	PlayAnim;
			float	CurrentTimeAnim;
			float	StartAnim;
			float	EndAnim;
			float	SpeedAnim;
			int	Mode;

			SAnimationStatus():
			LoopAnim(false), PlayAnim(false),
				CurrentTimeAnim(0), StartAnim(0),
				EndAnim(0), SpeedAnim(1), Mode(Mode::PlayList) {}
		};

		/// Destructor
		~CEntity(void);

		/// Loads a file animations
		/// @param fileName - name animation file
		void loadAnimation(std::string &fileName);

		/// Loads a file skeleton weight
		void loadSWT(std::string &fileName);

		/// Adds an animation to a playlist
		/// @param name - name loaded animations
		void addAnimToPlayList(std::string &name);

		/// Removes the animation from a playlist
		/// @param row - number of animations in the playlist
		void removeAnimToPlayList(uint row);

		/// Swaps animations to a playlist
		/// @param row1 - first number of animations in the playlist
		/// @param row2 - second number of animations in the playlist
		void swapAnimToPlayList(uint row1, uint row2); 

		/// Playback animation 
		void playbackAnim(bool play);

		/// Reset playlist and animation
		void reset();

		/// Get the total time of animation playlist
		/// @return total time of animation
		float getPlayListLength();

		/// get time length single animation
		float getAnimLength(std::string name);

		/// Get slot infomation
		void setSlotInfo(uint num, CSlotInfo& slotInfo) { _SlotInfo[num] = slotInfo; }

		/// Set use mode playlist or mixer
		void setMode(int mode) { _AnimationStatus.Mode = mode; }

		/// Set in place mode animation
		void setInPlace(bool enabled) { _inPlace = enabled; }

		/// Get in place mode
		bool getInPlace() { return _inPlace; }

		/// Set inc position
		void setIncPos(bool enabled) { _incPos = enabled; }

		/// Get inc position
		bool getIncPos() { return _incPos; }

		/// Get information about the current status of playing a playlist
		/// @return struct containing current information playback
		SAnimationStatus getStatus() { return _AnimationStatus; }

		/// Get name entity
		/// @return name entity
		std::string getName() { return _Name; }

		/// Get file name shape
		/// @return file name shape
		std::string getFileNameShape() { return _FileNameShape; }

		/// Get file name skeleton
		/// @return file name skeleton
		std::string getFileNameSkeleton() { return _FileNameSkeleton; }

		/// Get slot information
		CSlotInfo getSlotInfo(uint num) { return _SlotInfo[num]; }

		/// Get list loaded animations files
		std::vector<std::string>& getAnimationList() { return _AnimationList; }

		/// Get playlist animations
		std::vector<std::string>& getPlayListAnimation() { return _PlayListAnimation; }

		/// Get list loaded skeleton weight template files
		std::vector<std::string>& getSWTList() { return _SWTList; }

		/// Get game interface for manipulating Skeleton.
		NL3D::USkeleton getSkeleton() const { return _Skeleton; }

	private:
		/// Constructor
		CEntity(void);

		/// Update the animate from the playlist or channel mixer
		/// @param time - current time in second
		void update(NL3D::TAnimationTime time);

		void resetChannel();

		/// Update the animate from the playlist
		void animatePlayList(NL3D::TAnimationTime time);

		/// Update the animate from the mixer
		void animateChannelMixer();
		void addTransformation (NLMISC::CMatrix &current, NL3D::UAnimation *anim, 
			float begin, float end, 
			NL3D::UTrack *posTrack, NL3D::UTrack *rotquatTrack, 
			NL3D::UTrack *nextPosTrack, NL3D::UTrack *nextRotquatTrack, 
			bool removeLast);

		// The name of the entity
		std::string			_Name;
		std::string			_FileNameShape;
		std::string			_FileNameSkeleton;

		SAnimationStatus		_AnimationStatus;

		bool 				_inPlace;
		bool 				_incPos;

		float 				_CharacterScalePos;

		// The mesh instance associated to this entity
		NL3D::UInstance			_Instance;

		// The skeleton binded to the instance
		NL3D::USkeleton			_Skeleton;

		NL3D::UPlayList			*_PlayList;

		NL3D::UAnimationSet		*_AnimationSet;

		// Animation input file
		std::vector<std::string>	_AnimationList;

		// Skeleton weight input file
		std::vector<std::string>	_SWTList;

		// Play list animation
		std::vector<std::string >	_PlayListAnimation;

		// Slot info for this object
		CSlotInfo			_SlotInfo[NL3D::CChannelMixer::NumAnimationSlot];

		friend class CObjectViewerWidget;
	}; /* class CEntity */

	typedef std::map<std::string, CEntity>	CEntities;
	typedef CEntities::iterator		EIT;

} /* namespace NLQT */

#endif // ENTITY_H
